
#ifndef OBJECTPOOL_CPP_
#define OBJECTPOOL_CPP_

#include "ObjectPool.h"

template<class Object>
ObjectPool<Object>::ObjectPool(int pool_size,int grow_size,int object_size)
{
	this->mem_malloc_mode = MODE_USE_NEW;
	this->pool_grow_size = grow_size;
	this->object_size = object_size;
	this->pop_count = 0;
	this->object_count = 0;
	this->pool_max_size = pool_size;
	this->free_list_head=NULL;
	this->free_list_tail=NULL;
}

template<class Object>
ObjectPool<Object>::~ObjectPool()
{
	this->recycle();
}

template<class Object>
int ObjectPool<Object>::pop(Object *&obj)
{
	LockGuardReturn(RT_MUTEX,lock,rt_mutex,-1);
	if(this->free_list_head==NULL)
	{
		if(this->growth()!=0 && (this->free_list_head==NULL))
		{
			return -1;
		}
	}
	if(this->free_list_head->is_used)
	{
		return -1;
	}
	this->free_list_head->is_used = true;
	obj = (Object*)this->free_list_head->data;
	ObjectInfo *tmp = this->free_list_head->next;
	this->free_list_head->next = NULL;
	this->free_list_head = tmp;
	this->pop_count++;
	obj->reset();

	//LOG((DEBUG_LOG,"pop-->pool_name[%s] object_number[%d] used[%d]\n",
	//			this->pool_name.c_str(),this->object_count,this->pop_count));
	return 0;
}

template<class Object>
int ObjectPool<Object>::push( Object *obj)
{
	if(NULL==obj)
	{
		return -1;
	}
	LockGuardReturn(RT_MUTEX,lock,rt_mutex,-1);
	ObjectInfo *info_push = NULL;

	ObjectMap::iterator iter = this->object_map.find((int64_t)obj);
	if(iter==this->object_map.end())
	{
		return -1;
	}
	info_push = iter->second;

	if(info_push->is_used==false)
	{
		return -1;
	}
	if(this->free_list_head==NULL)
	{
		this->free_list_head =info_push;
	}
	info_push->is_used = false;
	this->free_list_tail->next = info_push;
	this->free_list_tail = info_push;
	this->free_list_tail->next = NULL;
	this->pop_count--;
	//LOG((DEBUG_LOG,"push-->pool_name[%s] object_number[%d] used[%d]\n",
	//		this->pool_name.c_str(),this->object_count,this->pop_count));
	return 0;
}

template<class Object>
int ObjectPool<Object>::growth()
{
	ObjectInfo *info = NULL;
	Object *obj = NULL;

	int obj_size =0;
	int i=0;
	for(;i<this->pool_grow_size;i++)
	{
		info = new ObjectInfo();
		if(info ==NULL)
		{
			return -1;
		}
		info->reset();

		this->mem_malloc(obj);
		if(obj == NULL)
		{
			delete info;
			info = NULL;
			return -1;
		}

		info->data = (void*)obj;
		info->size = sizeof(obj)+sizeof(ObjectInfo);
		if(i==0 && this->free_list_head==NULL)
		{
			this->free_list_head = info;
			this->free_list_tail = info;
		}
		else
		{
			this->free_list_tail->next = info;
			this->free_list_tail = info;
		}
		this->object_count++;
		this->object_map[(int64_t)obj]=info;
		obj_size = sizeof(*obj);
	}
	//LOG((DEBUG_LOG,"pool_name:[%s] object_count:[%d],grow[%d] total byte:[%d] ",
	//		this->pool_name.c_str(),this->object_count,
	//		i,this->object_count*obj_size));

	return 0;
}

/*
 * mode: MODE_USE_NEW-------->use C++ new;
 * 		 MODE_USE_NEW_SIZE--->use C++ new and specify size
 *		 MODE_USE_MALLOC ---->use C malloc
 * pool_size: max object in this pool
 * pool_name: pool name
 */
template<class Object>
void ObjectPool<Object>::set_malloc_mode(MemMallocMode mode)
{
	this->mem_malloc_mode = mode;
}

template<class Object>
void ObjectPool<Object>::set_pool_size(const int pool_size)
{
	this->pool_max_size = pool_size;
}

template<class Object>
void ObjectPool<Object>::set_growth_size(const int size)
{
	this->pool_grow_size = size;
}

template<class Object>
void ObjectPool<Object>::set_pool_name(const std::string pool_name)
{
	this->pool_name = pool_name;
}

template<class Object>
int ObjectPool<Object>::count_pop(void)
{
	return this->object_count;
}

template<class Object>
int ObjectPool<Object>::count_object(void)
{
	return this->pop_count;
}

template<class Object>
int ObjectPool<Object>::mem_malloc(Object *&obj)
{
	switch(this->mem_malloc_mode)
	{
		case MODE_USE_NEW_SIZE:
		{
			obj = new Object(this->object_size);
			break;
		}
		case MODE_USE_MALLOC:
		{
			if(this->object_size<=0)
			{
				return -1;
			}
			obj = (Object*)malloc(this->object_size);
			memset(obj,0,this->object_size);
			break;
		}
		case MODE_USE_NEW:
		default:
		{
			obj = new Object();
			break;
		}
	}
	return 0;
}

template<class Object>
void ObjectPool<Object>::recycle(void)
{
	int recycle_count = 0;
	LockGuardReturn(RT_MUTEX,lock,rt_mutex,;);

	for(ObjectMap::iterator iter = this->object_map.begin();
			iter!=this->object_map.end();++iter)
	{
		if (iter->second != NULL)
		{
			if (iter->second->data != NULL)
			{
				switch (this->mem_malloc_mode)
				{
					case MODE_USE_MALLOC:
					{
						free(iter->second->data);
						recycle_count++;
						break;
					}
					default:
					{
						delete (Object*) iter->second->data;
						iter->second->data = NULL;
						recycle_count++;
						break;
					}
				}
			}
			delete iter->second;
			iter->second = NULL;
		}
	}

	//LOG((INFO_LOG,"(%P|%t|%T) pool name:%s recycle:%d total:%d\n",
	//				this->pool_name.c_str(),recycle_count,this->object_count));
	this->object_map.clear();
	this->pool_name ="";
	this->pop_count =0;
	this->object_count =0;
}

#endif /*OBJECTPOOL_CPP_*/
